package com.lifeverse.service;

import com.lifeverse.entity.Decision;
import com.lifeverse.entity.LifeEntity;
import com.lifeverse.entity.Rule;
import com.lifeverse.entity.enums.RulePriority;
import com.lifeverse.repository.RuleRepository;
import com.lifeverse.util.JsonUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 规则引擎服务
 * 负责规则的管理、匹配和执行
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RuleEngine {
    
    private final RuleRepository ruleRepository;
    private final RuleConditionEvaluator conditionEvaluator;
    private final RuleActionExecutor actionExecutor;
    
    /**
     * 创建规则
     */
    @Transactional
    public Rule createRule(String name, String description, String category, 
                          RulePriority priority, String conditions, String actions) {
        log.info("创建规则 - 名称: {}, 分类: {}, 优先级: {}", name, category, priority);
        
        // 检查规则名称是否已存在
        if (ruleRepository.findByName(name).isPresent()) {
            throw new RuntimeException("规则名称已存在: " + name);
        }
        
        Rule rule = Rule.create(name, description, category, priority, conditions, actions);
        rule.setAuthor("SYSTEM");
        rule.setRuleVersion("1.0");
        
        Rule savedRule = ruleRepository.save(rule);
        log.info("规则创建成功 - ID: {}, 名称: {}", savedRule.getId(), savedRule.getName());
        
        return savedRule;
    }
    
    /**
     * 获取适用的规则
     */
    public List<Rule> getApplicableRules(Decision decision) {
        log.debug("获取适用规则 - 决策ID: {}, 类型: {}", decision.getId(), decision.getType());
        
        // 获取所有有效规则
        List<Rule> validRules = ruleRepository.findValidRules(LocalDateTime.now());
        
        // 过滤适用的规则
        List<Rule> applicableRules = validRules.stream()
                .filter(rule -> isRuleApplicable(rule, decision))
                .sorted(this::compareRulesByPriority)
                .collect(Collectors.toList());
        
        log.debug("找到 {} 个适用规则", applicableRules.size());
        return applicableRules;
    }
    
    /**
     * 获取分类下的适用规则
     */
    public List<Rule> getApplicableRulesByCategory(String category, Decision decision) {
        log.debug("获取分类适用规则 - 分类: {}, 决策ID: {}", category, decision.getId());
        
        List<Rule> categoryRules = ruleRepository.findValidRulesByCategory(category, LocalDateTime.now());
        
        return categoryRules.stream()
                .filter(rule -> isRuleApplicable(rule, decision))
                .sorted(this::compareRulesByPriority)
                .collect(Collectors.toList());
    }
    
    /**
     * 执行规则
     */
    @Transactional
    public RuleExecutionResult executeRule(Rule rule, Decision decision, Map<String, Object> context) {
        log.debug("执行规则 - 规则: {}, 决策ID: {}", rule.getName(), decision.getId());
        
        try {
            // 验证规则条件
            if (!conditionEvaluator.evaluate(rule.getConditions(), decision, context)) {
                log.debug("规则条件不满足 - 规则: {}", rule.getName());
                return RuleExecutionResult.failed("规则条件不满足");
            }
            
            // 执行规则动作
            RuleActionResult actionResult = actionExecutor.execute(rule.getActions(), decision, context);
            
            // 记录执行结果
            rule.recordExecution(actionResult.isSuccess());
            ruleRepository.save(rule);
            
            RuleExecutionResult result = new RuleExecutionResult();
            result.setSuccess(actionResult.isSuccess());
            result.setRuleName(rule.getName());
            result.setExecutionTime(LocalDateTime.now());
            result.setResults(actionResult.getResults());
            
            if (!actionResult.isSuccess()) {
                result.setErrorMessage(actionResult.getErrorMessage());
            }
            
            log.debug("规则执行完成 - 规则: {}, 结果: {}", rule.getName(), 
                     actionResult.isSuccess() ? "成功" : "失败");
            
            return result;
            
        } catch (Exception e) {
            log.error("规则执行异常 - 规则: {}", rule.getName(), e);
            
            rule.recordExecution(false);
            ruleRepository.save(rule);
            
            return RuleExecutionResult.failed("规则执行异常: " + e.getMessage());
        }
    }
    
    /**
     * 批量执行规则
     */
    @Transactional
    public List<RuleExecutionResult> executeRules(List<Rule> rules, Decision decision, 
                                                 Map<String, Object> context) {
        log.debug("批量执行规则 - 规则数量: {}, 决策ID: {}", rules.size(), decision.getId());
        
        List<RuleExecutionResult> results = new ArrayList<>();
        
        for (Rule rule : rules) {
            RuleExecutionResult result = executeRule(rule, decision, context);
            results.add(result);
            
            // 如果是关键规则执行失败，可能需要停止后续执行
            if (!result.isSuccess() && rule.getPriority() == RulePriority.CRITICAL) {
                log.warn("关键规则执行失败，停止后续规则执行 - 规则: {}", rule.getName());
                break;
            }
        }
        
        log.debug("批量规则执行完成 - 总数: {}, 成功: {}", 
                 results.size(), results.stream().mapToInt(r -> r.isSuccess() ? 1 : 0).sum());
        
        return results;
    }
    
    /**
     * 更新规则
     */
    @Transactional
    public Rule updateRule(Long ruleId, String conditions, String actions, String description) {
        log.info("更新规则 - ID: {}", ruleId);
        
        Rule rule = ruleRepository.findById(ruleId)
                .orElseThrow(() -> new RuntimeException("规则不存在: " + ruleId));
        
        rule.setConditions(conditions);
        rule.setActions(actions);
        if (description != null) {
            rule.setDescription(description);
        }
        
        // 更新版本号
        String currentVersion = rule.getRuleVersion();
        String newVersion = incrementVersion(currentVersion);
        rule.setRuleVersion(newVersion);
        
        Rule savedRule = ruleRepository.save(rule);
        log.info("规则更新成功 - ID: {}, 新版本: {}", ruleId, newVersion);
        
        return savedRule;
    }
    
    /**
     * 启用/禁用规则
     */
    @Transactional
    public Rule toggleRule(Long ruleId, boolean enabled) {
        log.info("切换规则状态 - ID: {}, 启用: {}", ruleId, enabled);
        
        Rule rule = ruleRepository.findById(ruleId)
                .orElseThrow(() -> new RuntimeException("规则不存在: " + ruleId));
        
        rule.setEnabled(enabled);
        Rule savedRule = ruleRepository.save(rule);
        
        log.info("规则状态切换成功 - ID: {}, 状态: {}", ruleId, enabled ? "启用" : "禁用");
        return savedRule;
    }
    
    /**
     * 获取规则统计信息
     */
    public RuleStatistics getRuleStatistics() {
        log.debug("获取规则统计信息");
        
        long totalRules = ruleRepository.count();
        long enabledRules = ruleRepository.countByEnabledTrue();
        long disabledRules = totalRules - enabledRules;
        
        Map<RulePriority, Long> priorityStats = Arrays.stream(RulePriority.values())
                .collect(Collectors.toMap(
                        priority -> priority,
                        priority -> ruleRepository.countByPriority(priority)
                ));
        
        // 获取成功率统计
        List<Rule> allRules = ruleRepository.findAll();
        double averageSuccessRate = allRules.stream()
                .filter(rule -> rule.getExecutionCount() > 0)
                .mapToDouble(Rule::getSuccessRate)
                .average()
                .orElse(0.0);
        
        RuleStatistics stats = new RuleStatistics();
        stats.setTotalRules(totalRules);
        stats.setEnabledRules(enabledRules);
        stats.setDisabledRules(disabledRules);
        stats.setPriorityStats(priorityStats);
        stats.setAverageSuccessRate(averageSuccessRate);
        
        return stats;
    }
    
    /**
     * 清理过期规则
     */
    @Transactional
    public int cleanupExpiredRules() {
        log.info("清理过期规则");
        
        LocalDateTime now = LocalDateTime.now();
        List<Rule> expiredRules = ruleRepository.findAll().stream()
                .filter(rule -> rule.getValidUntil() != null && rule.getValidUntil().isBefore(now))
                .collect(Collectors.toList());
        
        for (Rule rule : expiredRules) {
            rule.setEnabled(false);
            ruleRepository.save(rule);
        }
        
        log.info("清理过期规则完成 - 数量: {}", expiredRules.size());
        return expiredRules.size();
    }
    
    /**
     * 判断规则是否适用
     */
    private boolean isRuleApplicable(Rule rule, Decision decision) {
        try {
            // 基本检查
            if (!rule.isValid()) {
                return false;
            }
            
            // 检查规则分类是否匹配决策类型
            if (isRuleCategoryMatched(rule.getCategory(), decision)) {
                return true;
            }
            
            // 检查规则条件（简化版本，实际应该更复杂）
            return conditionEvaluator.quickCheck(rule.getConditions(), decision);
            
        } catch (Exception e) {
            log.warn("检查规则适用性时出错 - 规则: {}", rule.getName(), e);
            return false;
        }
    }
    
    /**
     * 检查规则分类是否匹配
     */
    private boolean isRuleCategoryMatched(String ruleCategory, Decision decision) {
        // 通用规则适用于所有决策
        if ("GENERAL".equals(ruleCategory)) {
            return true;
        }
        
        // 根据决策类型匹配规则分类
        switch (decision.getType()) {
            case RESOURCE_ALLOCATION:
                return "RESOURCE".equals(ruleCategory);
            case COLLABORATION:
                return "COLLABORATION".equals(ruleCategory);
            case EVOLUTION:
                return "EVOLUTION".equals(ruleCategory);
            case RELATIONSHIP:
                return "RELATIONSHIP".equals(ruleCategory);
            default:
                return "GENERAL".equals(ruleCategory);
        }
    }
    
    /**
     * 比较规则优先级
     */
    private int compareRulesByPriority(Rule r1, Rule r2) {
        // 首先按优先级排序（高优先级在前）
        int priorityCompare = r2.getPriority().getLevel() - r1.getPriority().getLevel();
        if (priorityCompare != 0) {
            return priorityCompare;
        }
        
        // 优先级相同时，按成功率排序
        double successRate1 = r1.getSuccessRate();
        double successRate2 = r2.getSuccessRate();
        int successRateCompare = Double.compare(successRate2, successRate1);
        if (successRateCompare != 0) {
            return successRateCompare;
        }
        
        // 最后按名称排序
        return r1.getName().compareTo(r2.getName());
    }
    
    /**
     * 增加版本号
     */
    private String incrementVersion(String currentVersion) {
        try {
            String[] parts = currentVersion.split("\\.");
            if (parts.length >= 2) {
                int major = Integer.parseInt(parts[0]);
                int minor = Integer.parseInt(parts[1]);
                return major + "." + (minor + 1);
            }
        } catch (Exception e) {
            log.warn("解析版本号失败: {}", currentVersion, e);
        }
        return "1.1";
    }
    
    // 内部类定义
    public static class RuleExecutionResult {
        private boolean success;
        private String ruleName;
        private String errorMessage;
        private LocalDateTime executionTime;
        private Map<String, Object> results;
        
        public static RuleExecutionResult failed(String errorMessage) {
            RuleExecutionResult result = new RuleExecutionResult();
            result.setSuccess(false);
            result.setErrorMessage(errorMessage);
            result.setExecutionTime(LocalDateTime.now());
            return result;
        }
        
        // getters and setters
        public boolean isSuccess() { return success; }
        public void setSuccess(boolean success) { this.success = success; }
        public String getRuleName() { return ruleName; }
        public void setRuleName(String ruleName) { this.ruleName = ruleName; }
        public String getErrorMessage() { return errorMessage; }
        public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
        public LocalDateTime getExecutionTime() { return executionTime; }
        public void setExecutionTime(LocalDateTime executionTime) { this.executionTime = executionTime; }
        public Map<String, Object> getResults() { return results; }
        public void setResults(Map<String, Object> results) { this.results = results; }
    }
    
    public static class RuleActionResult {
        private boolean success;
        private String errorMessage;
        private Map<String, Object> results;
        
        // getters and setters
        public boolean isSuccess() { return success; }
        public void setSuccess(boolean success) { this.success = success; }
        public String getErrorMessage() { return errorMessage; }
        public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
        public Map<String, Object> getResults() { return results; }
        public void setResults(Map<String, Object> results) { this.results = results; }
    }
    
    public static class RuleStatistics {
        private long totalRules;
        private long enabledRules;
        private long disabledRules;
        private Map<RulePriority, Long> priorityStats;
        private double averageSuccessRate;
        
        // getters and setters
        public long getTotalRules() { return totalRules; }
        public void setTotalRules(long totalRules) { this.totalRules = totalRules; }
        public long getEnabledRules() { return enabledRules; }
        public void setEnabledRules(long enabledRules) { this.enabledRules = enabledRules; }
        public long getDisabledRules() { return disabledRules; }
        public void setDisabledRules(long disabledRules) { this.disabledRules = disabledRules; }
        public Map<RulePriority, Long> getPriorityStats() { return priorityStats; }
        public void setPriorityStats(Map<RulePriority, Long> priorityStats) { this.priorityStats = priorityStats; }
        public double getAverageSuccessRate() { return averageSuccessRate; }
        public void setAverageSuccessRate(double averageSuccessRate) { this.averageSuccessRate = averageSuccessRate; }
    }
}